package avicit.bdp.dds.api.controller;

import avicit.bdp.common.service.dto.CommonTypeDTO;
import avicit.bdp.common.service.dto.DataSourceDTO;
import avicit.bdp.common.service.service.DataSourceService;
import avicit.bdp.common.database.ColumnMeta;
import avicit.bdp.common.database.TableMeta;
import avicit.bdp.dds.api.dto.SqlInputDto;
import avicit.bdp.dds.api.service.ProjectService;
import avicit.bdp.dds.dao.entity.Project;
import avicit.platform6.core.exception.BusinessException;
import avicit.platform6.core.rest.msg.QueryRespBean;
import avicit.platform6.core.rest.msg.ResponseMsg;
import com.github.pagehelper.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.annotations.ApiIgnore;

/** 工作空间数据源管理REST接口 */
@RestController
@Api(tags = "工作空间数据源管理REST接口")
@RequestMapping("/api/bdp/dds/datasource")
public class DataSourceRest {

  private static final Logger logger = LoggerFactory.getLogger(DataSourceRest.class);

  @Autowired private DataSourceService dataSourceService;

  @Autowired private ProjectService projectService;

  /**
   * 工作台-数据源管理-新增数据源时，根据空间创建者获取数据源列表 注意： `1、需要剔除已导入的数据源
   *
   * <p>根据空间ID查询公共数据源列表
   */
  @ApiOperation(value = "根据空间ID查询公共数据源列表")
  @ApiImplicitParams({
    @ApiImplicitParam(name = "projectId", value = "数据空间id", dataType = "String"),
    @ApiImplicitParam(name = "typeId", value = "末级节点分类Id", dataType = "String"),
    @ApiImplicitParam(name = "keyWords", value = "查询关键字", dataType = "String"),
    @ApiImplicitParam(name = "pageNo", value = "当前页", dataType = "Int"),
    @ApiImplicitParam(name = "pageSize", value = "每页大小", dataType = "Int")
  })
  @GetMapping(value = "/searchDataSource")
  public ResponseMsg<QueryRespBean<DataSourceDTO>> searchDataSource(
      @RequestParam String projectId,
      @RequestParam String typeId,
      @RequestParam(required = false) String keyWords,
      @RequestParam(defaultValue = "1", required = false) Integer pageNo,
      @RequestParam(defaultValue = "10", required = false) Integer pageSize,
      @RequestParam(required = false) String secretLevel) {
    ResponseMsg<QueryRespBean<DataSourceDTO>> responseMsg = new ResponseMsg<>();
    if (StringUtils.isEmpty(projectId)) {
      return responseMsg;
    }

    // 根据空间创建者过滤公共数据源权限
    Project project = this.projectService.selectByPrimaryKey(projectId);
    String projectCreatedBy = project.getCreatedBy();
    QueryRespBean<DataSourceDTO> allDs =
        this.dataSourceService.searchDataSource(projectCreatedBy, typeId, keyWords, pageNo, pageSize, secretLevel);
    if (allDs == null || CollectionUtils.isEmpty(allDs.getResult())) {
      responseMsg.setResponseBody(allDs);
      return responseMsg;
    }

    // 获取已导入数据源
    List<String> importedDsIdList = this.dataSourceService.getImportedDatasourceIdList(projectId);

    // 获取未导入数据源(公共数据源-已导入数据源)
    Map<String, DataSourceDTO> allDsMap =
        allDs.getResult().stream().collect(Collectors.toMap(DataSourceDTO::getId, obj -> obj));
    for (String dsId : importedDsIdList) {
      if (StringUtils.isNotEmpty(dsId) && allDsMap.containsKey(dsId)) {
        allDsMap.remove(dsId);
      }
    }
    Page<DataSourceDTO> page = new Page<>(pageNo, pageSize);
    page.setTotal(allDsMap.values().size());
    page.addAll(allDsMap.values());
    allDs.setResult(page);
    responseMsg.setResponseBody(allDs);

    return responseMsg;
  }

  /** 查询数据源详情 */
  @ApiOperation(value = "查询数据源")
  @ApiImplicitParam(name = "id", value = "id", dataType = "String")
  @GetMapping(value = "/queryDataSourceById")
  public ResponseMsg<DataSourceDTO> queryDataSourceById(@RequestParam("id") String id) {
    logger.info("query datasource: {}", id);
    ResponseMsg<DataSourceDTO> responseMsg = new ResponseMsg<>();
    responseMsg.setResponseBody(dataSourceService.queryDataSourceById(id));
    return responseMsg;
  }

  /**
   * 查询数据源列表
   *
   * @param type data source typ
   * @param structure 结构：0-结构化 1-非结构化 2-半结构化
   * @param keyWords key word
   */
  @ApiOperation(value = "查询数据源列表")
  @ApiImplicitParams({
    @ApiImplicitParam(name = "type", value = "数据源类型", dataType = "String"),
    @ApiImplicitParam(name = "structure", value = "数据源结构", dataType = "Int"),
    @ApiImplicitParam(name = "keyWords", value = "关键字", dataType = "String")
  })
  @GetMapping(value = "/list")
  public ResponseMsg<List<DataSourceDTO>> queryDataSourceList(
      @RequestParam(value = "type", required = false) String type,
      @RequestParam(value = "structure", required = false) Integer structure,
      @RequestParam(value = "keyWords", required = false) String keyWords) {
    logger.info("query datasource type: {}, structure: {}, keyWords:{}", type, structure, keyWords);

    ResponseMsg<List<DataSourceDTO>> responseMsg = new ResponseMsg<>();
    responseMsg.setResponseBody(dataSourceService.queryDataSourceList(type, structure, keyWords, null));
    return responseMsg;
  }

  /** 查询公共数据源和项目数据源 */
  @ApiOperation(value = "查询公共数据源和项目数据源")
  @ApiImplicitParam(name = "projectId", value = "数据空间id", dataType = "String")
  @GetMapping(value = "/getDatasourceList")
  public ResponseMsg<Map<String, List<CommonTypeDTO>>> getDatasourceList(
      @RequestParam(required = false) String projectId) throws Exception {
    ResponseMsg<Map<String, List<CommonTypeDTO>>> responseMsg = new ResponseMsg<>();
    responseMsg.setResponseBody(dataSourceService.getDatasourceList(projectId));
    return responseMsg;
  }

  /** 根据数据源ID获取所有表 */
  @ApiOperation(value = "根据数据源ID获取所有表")
  @ApiImplicitParam(name = "dataSourceId", value = "数据源id", dataType = "String")
  @GetMapping(value = "/getTableListByDatasourceId")
  public ResponseMsg<List<String>> getTableListByDatasourceId(@RequestParam String dataSourceId)
      throws Exception {
    ResponseMsg<List<String>> responseMsg = new ResponseMsg<>();
    List<TableMeta> tableMetaList =
        dataSourceService.getTableListByDatasourceId(dataSourceId, false);
    if (CollectionUtils.isNotEmpty(tableMetaList)) {
      List<String> tables =
          tableMetaList.stream().map(TableMeta::getName).collect(Collectors.toList());
      responseMsg.setResponseBody(tables);
    }
    return responseMsg;
  }

  /** 根据数据源id和表名获取所有列 */
  @ApiOperation(value = "根据数据源id和表名获取所有列")
  @ApiImplicitParams({
    @ApiImplicitParam(name = "datasourceId", value = "数据源id", dataType = "String"),
    @ApiImplicitParam(name = "tableName", value = "表名", dataType = "String")
  })
  @GetMapping("/getColumnList")
  public ResponseMsg<List<ColumnMeta>> getColumnList(
      @RequestParam String datasourceId, @RequestParam String tableName) throws Exception {
    ResponseMsg<List<ColumnMeta>> responseMsg = new ResponseMsg<>();
    responseMsg.setResponseBody(dataSourceService.getColumnListBySpark(datasourceId, tableName));
    return responseMsg;
  }

  /** 根据sql获取所有列 */
  @ApiOperation(value = "根据sql获取所有列")
  @PostMapping("/getColumnListBySql")
  public ResponseMsg<List<ColumnMeta>> getColumnListBySql(@RequestBody SqlInputDto sqlInputDto)
      throws Exception {
    ResponseMsg<List<ColumnMeta>> responseMsg = new ResponseMsg<>();
    if (StringUtils.isBlank(sqlInputDto.getDatasourceId())) {
      throw new BusinessException("请输入数据源");
    }
    if (StringUtils.isBlank(sqlInputDto.getSql())) {
      throw new BusinessException("请输入sql脚本");
    }
    responseMsg.setResponseBody(
        dataSourceService.getColumnListBySqlBySpark(
            sqlInputDto.getDatasourceId(), sqlInputDto.getSql()));
    return responseMsg;
  }

  /** 根据表获取列 */
  @ApiOperation(value = "获取列信息")
  @ApiImplicitParam(name = "tableId", value = "表id", dataType = "String")
  @GetMapping("/getColumnListByTableId")
  public ResponseMsg<List<ColumnMeta>> getColumnListByTableId(@RequestParam String tableId) {
    ResponseMsg<List<ColumnMeta>> responseMsg = new ResponseMsg<>();
    if (StringUtils.isBlank(tableId)) {
      throw new BusinessException("请选择模型");
    }
    List<ColumnMeta> result = dataSourceService.getColumnListByTableId(tableId);
    responseMsg.setResponseBody(result);
    return responseMsg;
  }

  /** 模型输入获取字段信息 */
  @ApiOperation(value = "获取列信息")
  @ApiImplicitParam(name = "modelId", value = "模型id", dataType = "String")
  @GetMapping("/getColumnListByModelId")
  public ResponseMsg<List<ColumnMeta>> getColumnListByModelId(@RequestParam String modelId) {
    ResponseMsg<List<ColumnMeta>> responseMsg = new ResponseMsg<>();
    if (StringUtils.isBlank(modelId)) {
      throw new BusinessException("请选择模型");
    }
    List<ColumnMeta> result = dataSourceService.getColumnListByModelIdBySpark(modelId);
    responseMsg.setResponseBody(result);
    return responseMsg;
  }

  /** 删除引用数据源 */
  @ApiOperation(value = "删除引用数据源")
  @ApiImplicitParams({
    @ApiImplicitParam(
        name = "id",
        value = "id",
        dataType = "String",
        paramType = "body",
        required = true),
    @ApiImplicitParam(
        name = "projectId",
        value = "数据空间id",
        dataType = "String",
        paramType = "body",
        required = true)
  })
  @PostMapping("/deleteProDs")
  public ResponseMsg<Integer> deleteProDs(@ApiIgnore @RequestBody Map<String, String> queryMap) {
    ResponseMsg<Integer> responseMsg = new ResponseMsg<>();
    dataSourceService.deleteProDs(queryMap);
    return responseMsg;
  }
}
